{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#协同过滤推荐算法简单代码实现（基于物品、jaccard）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from pprint import pprint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "       ItemA  ItemB  ItemC  ItemD  ItemE\n",
      "User1      1      0      1      1      0\n",
      "User2      1      0      0      1      1\n",
      "User3      1      0      1      0      0\n",
      "User4      0      1      0      1      1\n",
      "User5      1      1      1      0      1\n",
      "Index(['User1', 'User2', 'User3', 'User4', 'User5'], dtype='object')\n",
      "Index(['ItemA', 'ItemB', 'ItemC', 'ItemD', 'ItemE'], dtype='object')\n"
     ]
    }
   ],
   "source": [
    "#构建用户购买记录数据集（1买了，0没买）\n",
    "users = [\"User1\",\"User2\",\"User3\",\"User4\",\"User5\",]\n",
    "items = [\"ItemA\",\"ItemB\",\"ItemC\",\"ItemD\",\"ItemE\"]\n",
    "datasets = [\n",
    "    [1,0,1,1,0],\n",
    "    [1,0,0,1,1],\n",
    "    [1,0,1,0,0],\n",
    "    [0,1,0,1,1],\n",
    "    [1,1,1,0,1],\n",
    "]\n",
    "df = pd.DataFrame(datasets,columns=items,index=users)\n",
    "print(df)\n",
    "print(df.index)\n",
    "print(df.columns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "物品之间的相似度\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.7/site-packages/sklearn/metrics/pairwise.py:1761: DataConversionWarning: Data was converted to boolean for metric jaccard\n",
      "  warnings.warn(msg, DataConversionWarning)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ItemA</th>\n",
       "      <th>ItemB</th>\n",
       "      <th>ItemC</th>\n",
       "      <th>ItemD</th>\n",
       "      <th>ItemE</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>ItemA</th>\n",
       "      <td>1.00</td>\n",
       "      <td>0.200000</td>\n",
       "      <td>0.75</td>\n",
       "      <td>0.40</td>\n",
       "      <td>0.400000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ItemB</th>\n",
       "      <td>0.20</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.25</td>\n",
       "      <td>0.25</td>\n",
       "      <td>0.666667</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ItemC</th>\n",
       "      <td>0.75</td>\n",
       "      <td>0.250000</td>\n",
       "      <td>1.00</td>\n",
       "      <td>0.20</td>\n",
       "      <td>0.200000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ItemD</th>\n",
       "      <td>0.40</td>\n",
       "      <td>0.250000</td>\n",
       "      <td>0.20</td>\n",
       "      <td>1.00</td>\n",
       "      <td>0.500000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ItemE</th>\n",
       "      <td>0.40</td>\n",
       "      <td>0.666667</td>\n",
       "      <td>0.20</td>\n",
       "      <td>0.50</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       ItemA     ItemB  ItemC  ItemD     ItemE\n",
       "ItemA   1.00  0.200000   0.75   0.40  0.400000\n",
       "ItemB   0.20  1.000000   0.25   0.25  0.666667\n",
       "ItemC   0.75  0.250000   1.00   0.20  0.200000\n",
       "ItemD   0.40  0.250000   0.20   1.00  0.500000\n",
       "ItemE   0.40  0.666667   0.20   0.50  1.000000"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics.pairwise import pairwise_distances\n",
    "# 计算物品间相似度(相似度 = 1-杰卡德距离) 默认是行\n",
    "item_similar = 1 - pairwise_distances(df.T.values,metric='jaccard')\n",
    "item_similar = pd.DataFrame(item_similar,columns=items,index=items)\n",
    "print(\"物品之间的相似度\")\n",
    "item_similar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "每个商品最相似的两个商品\n",
      "{'ItemA': ['ItemC', 'ItemE'],\n",
      " 'ItemB': ['ItemE', 'ItemD'],\n",
      " 'ItemC': ['ItemA', 'ItemB'],\n",
      " 'ItemD': ['ItemE', 'ItemA'],\n",
      " 'ItemE': ['ItemB', 'ItemD']}\n"
     ]
    }
   ],
   "source": [
    "topN_items = {}\n",
    "for i in item_similar.columns:\n",
    "    _df = item_similar.loc[i].drop(i)\n",
    "    _df_sorted = _df.sort_values(ascending = False)\n",
    "    top2 = list(_df_sorted.index[:2])\n",
    "    topN_items[i] = top2\n",
    "    \n",
    "print(\"每个商品最相似的两个商品\")\n",
    "pprint(topN_items)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "基于物品的推荐\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'User1': {'ItemB', 'ItemE'},\n",
       " 'User2': {'ItemB', 'ItemC'},\n",
       " 'User3': {'ItemB', 'ItemE'},\n",
       " 'User4': {'ItemA'},\n",
       " 'User5': {'ItemD'}}"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rs_items = {}\n",
    "for user in df.index:#遍历所有用户\n",
    "    rs_item = set()\n",
    "    for item in df.loc[user].replace(0,np.nan).dropna().index:#取出每个用户购买物品\n",
    "        rs_item = rs_item.union(set(topN_items[item]))#每个物品找出最相似的物品，给用户推荐\n",
    "    rs_item -= set(df.loc[user].replace(0,np.nan).dropna().index)#删去用户自己购买的\n",
    "    rs_items[user] = rs_item\n",
    "\n",
    "print(\"基于物品的推荐\")\n",
    "rs_items"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
